package cn.shujuhai.cms.service.impl;

import cn.shujuhai.cms.domain.SysChannel;
import cn.shujuhai.cms.domain.SysTemplate;
import cn.shujuhai.cms.domain.SysTemplateType;
import cn.shujuhai.cms.mapper.SysTemplateMapper;
import cn.shujuhai.cms.mapper.SysTemplateTypeMapper;
import cn.shujuhai.cms.service.SysChannelService;
import cn.shujuhai.cms.service.SysTemplateService;
import cn.shujuhai.cms.service.SysTemplateTypeService;
import cn.shujuhai.cms.service.thymeleaf.StaticHtmlService;
import cn.shujuhai.common.pluging.data.ResultVo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/**
 * @Author: myh
 * @Date: 2024/12/5 12:01
 * @Description: 针对表【sys_template(模板)】的数据库操作Service实现
 **/
@Service
@RequiredArgsConstructor
public class SysTemplateServiceImpl extends ServiceImpl<SysTemplateMapper, SysTemplate>
        implements SysTemplateService {

    @Value("${template.static.thymeleafUrl}")
    private String thymeleafUrl;  //静态文件管理根目录路径

    //列表详细页模板类型代码
    private static final String code = "LIST_DETAIL";
    final SysTemplateTypeService sysTemplateTypeService;
    final SysTemplateTypeMapper sysTemplateTypeMapper;
    final SysChannelService sysChannelService;
    final StaticHtmlService staticHtmlService;

    /**
     * 获取模板信息分页
     *
     * @param templateName 模板名称
     * @param type         模板类型
     * @param pageNum      页码
     * @param pageSize     每页大小
     * @return 模板列表的分页结果
     */
    @Override
    public PageInfo<SysTemplate> getPagedTemplatesByNameAndType(String templateName, String type, int pageNum, int pageSize) {
        // 开启分页
        PageHelper.startPage(pageNum, pageSize);
        MPJLambdaWrapper<SysTemplate> wrapper = queryTemplate();
        // 添加查询条件（模板名称）
        wrapper.like(SysTemplate::getTemplateName, templateName);
        wrapper.like(SysTemplateType::getTypeName, type);
        wrapper.orderByDesc(SysTemplate::getTemplateId);
        // 执行查询并获取结果
        List<SysTemplate> templates = this.baseMapper.selectJoinList(SysTemplate.class, wrapper);
        // 使用 PageInfo 包装结果并返回
        return new PageInfo<>(templates);
    }

    /**
     * 获取模板类型列表
     *
     * @return 模板类型列表
     */
    @Override
    public List<SysTemplateType> getTemplateTypeList() {
        return this.sysTemplateTypeService.list(Wrappers.<SysTemplateType>lambdaQuery().eq(SysTemplateType::getType, 1));
    }

    /**
     * 获取模板类型列表(公共模板)
     *
     * @return 模板类型列表
     */
    @Override
    public List<SysTemplateType> getTypeList() {
        return this.sysTemplateTypeService.list();
    }

    /**
     * 新增模板
     *
     * @param sysTemplate 模板对象
     * @return 结果信息
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResultVo<?> addTemplate(SysTemplate sysTemplate) {
        if (verifyTemplateUrl(sysTemplate.getTemplateUrl())) {
            return ResultVo.failure("模板路径已存在！");
        }
        boolean save = this.save(sysTemplate);
        if (save) {
            try {
                String decode = URLDecoder.decode(new String(sysTemplate.getContent(), StandardCharsets.UTF_8), StandardCharsets.UTF_8);
                this.saveContentToFile(decode.getBytes(StandardCharsets.UTF_8), sysTemplate.getTemplateUrl());
                return ResultVo.success();
            } catch (IOException e) {
                throw new RuntimeException("文件保存失败: " + e.getMessage(), e);
            }
        }
        return ResultVo.failure("新增失败");
    }

    /**
     * 根据模板ID获取模板内容
     *
     * @param templateId 模板ID
     * @return 模板内容结果信息
     */
    @Override
    public SysTemplate getTemplateById(Long templateId) {
        MPJLambdaWrapper<SysTemplate> wrapper = queryTemplate();
        if (templateId != null) {
            wrapper.eq(SysTemplate::getTemplateId, templateId);
        }
        return this.baseMapper.selectOne(wrapper);
    }

    /**
     * 修改模板
     *
     * @param sysTemplate 模板对象
     * @return 结果信息
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResultVo<?> update(SysTemplate sysTemplate) {
        SysTemplate oldSysTemplate = this.getById(sysTemplate.getTemplateId());
        String templateUrl = oldSysTemplate.getTemplateUrl();
        if ((!templateUrl.equals(sysTemplate.getTemplateUrl())) && verifyTemplateUrl(sysTemplate.getTemplateUrl())) {
            return ResultVo.failure("模板路径已存在！");
        }
        // 更新模板数据
        boolean updatedById = this.updateById(sysTemplate);
        if (updatedById) {
            boolean deleteFile = deleteFile(templateUrl);
            if (deleteFile) {
                try {
                    String decode = URLDecoder.decode(new String(sysTemplate.getContent(), StandardCharsets.UTF_8), StandardCharsets.UTF_8);
                    this.saveContentToFile(decode.getBytes(StandardCharsets.UTF_8), sysTemplate.getTemplateUrl());
                    this.staticHtmlService.updateStaticHtml(sysTemplate);
                    return ResultVo.success();
                } catch (IOException e) {
                    throw new RuntimeException("文件保存失败: " + e.getMessage(), e);
                }
            } else {
                throw new RuntimeException("文件保存失败!");
            }
        }
        return ResultVo.failure("修改失败");
    }


    /**
     * 验证模板路径是否存在
     *
     * @param templateUrl 模板路径
     * @return 如果模板路径存在，则返回 true；否则返回 false
     */
    private boolean verifyTemplateUrl(String templateUrl) {
        return this.getOne(Wrappers.<SysTemplate>lambdaQuery().eq(SysTemplate::getTemplateUrl, templateUrl)) != null;
    }

    /**
     * 删除模板
     *
     * @param templateId 模板ID
     * @return 结果信息
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public ResultVo<?> delById(Long templateId) {
        List<SysChannel> sysChannelList = this.sysChannelService.list(Wrappers.<SysChannel>lambdaQuery().eq(SysChannel::getTemplateId, templateId));
        if (!sysChannelList.isEmpty()) {
            return ResultVo.failure("模板已被使用，不能删除！");
        }
        SysTemplate sysTemplate = this.getById(templateId);
        this.removeById(templateId);
        boolean deleteFile = deleteFile(sysTemplate.getTemplateUrl());
        if (deleteFile) {
            return ResultVo.success();
        }
        throw new RuntimeException("文件删除失败!");
    }

    /**
     * 根据模板类型ID获取模板列表
     *
     * @param templateTypeId 模板类型ID
     * @return 模板列表结果信息
     */
    @Override
    public List<SysTemplate> getTemplateListByTypeId(Long templateTypeId) {
        return this.list(Wrappers.<SysTemplate>lambdaQuery().eq(SysTemplate::getType, templateTypeId));
    }

    /**
     * 获取所有模板详细页列表
     *
     * @return 模板详细页列表结果信息
     */
    @Override
    public List<SysTemplate> getListByCode() {
        SysTemplateType templateType = this.sysTemplateTypeService.getOne(Wrappers.<SysTemplateType>lambdaQuery().eq(SysTemplateType::getCode, code));
        return this.list(Wrappers.<SysTemplate>lambdaQuery().eq(SysTemplate::getType, templateType.getTemplateTypeId()));
    }

    /**
     * 模板与类型表的多表联查
     *
     * @return 多表联查结果
     */
    private MPJLambdaWrapper<SysTemplate> queryTemplate() {
        // 使用 MPJLambdaWrapper 实现多表联查
        return new MPJLambdaWrapper<SysTemplate>()
                .selectAll(SysTemplate.class) // 查询所有模板表的字段
                .select(SysTemplateType::getTypeName) // 查询模板类型表的 typeName
                .leftJoin(SysTemplateType.class, SysTemplateType::getTemplateTypeId, SysTemplate::getType); // 联接模板类型表
    }

    /**
     * 保存模板内容到文件中
     *
     * @param filePath 文件路径
     * @throws IOException IOException
     */
    public void saveContentToFile(byte[] content, String filePath) throws IOException {
        Path path = Paths.get(thymeleafUrl, filePath);
        File file = path.toFile();
        File parentDir = file.getParentFile();
        if (!parentDir.exists()) {
            throw new IOException("no Directory" + parentDir.getAbsolutePath());
        }
        if (file.exists()) {
            throw new IOException("File already exists: " + file);
        }
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(content);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 删除模板文件
     *
     * @param filePath 文件路径
     * @return 删除成功返回true，否则false
     */
    public boolean deleteFile(String filePath) {
        filePath = thymeleafUrl + filePath;
        File file = new File(filePath);
        if (file.exists()) {
            return file.delete();
        } else {
            return true;
        }
    }
}